'use strict'

const net = require('net');

class Connection {
  constructor(id, ip, port, options) {
    this._id = id;
    this._ip = ip;
    this._port = port;

    // register handler
    this._closeHandler = options.closeHandler;
    this._frameHandler = options.frameHandler;
    this._connHandler = options.connHandler;
    this._onFrameReady = options.onFrameReady;

    // internal data buffer
    this._buf = null;

    this._local_close = false;       
    
    // prepare the socket client
    this._socket = new net.Socket();        
    this._socket.on('close', this._onClosed.bind(this));
    this._socket.on('data', this._onData.bind(this));
    this._socket.on('error', this._onError.bind(this));

    this.isOnline = false;
    this.init();
  }

  init() {
    if (this.isOnline) {
      this._socket.destroy();
    }
    this._socket.connect(this._port, this._ip, this._onConnect.bind(this));
  }

  _onClosed() {
    if(this._closeHandler) {
      this._closeHandler(this._id, this._local_close ? false : true);  
    }    
    this._isOnline = false;
  }

  _onData(data) {
    console.log(data);
    console.log(this._buf);    
    if (this._buf !== null) {
      let tmp_buf = Buffer.alloc(this._buf.length + data.length);
      this._buf.copy(tmp_buf, 0, this._buf.length);
      data.copy(tmp_buf, this._buf.length, 0);
      this._buf = null;
      this._buf = tmp_buf;
    } else {
      this._buf = data;
    }

    let [frame, start, end] = this._frameHandler(this._buf);
    console.log(start, end);
    if (frame) {
      this._onFrameReady(frame);            
      this._buf = (end < this._buf.length) ? this._buf.slice(end) : null;
    } else {
      this._buf = (start < this._buf.length) ? this._buf.slice(start) : null;      
    }
    data = null;
    console.log(this._buf);
  }

  _onConnect() {
    if (this._connHandler) {
      this._connHandler(this._id);
    }    
    this._isOnline = true;
    this._local_close = false;
  }

  _onError() {
    this._local_close = true;
    this._socket.end();
  }

  write(data) {
    this._socket.write(data);
  }

  close() {
    this._local_close = true;
    this._socket.destroy();
  }
}

/**
 * Export
 */

// const df = require('../protocol/dataFrame');
// if (!module.parent) {
//   let c = new Connection(2, '127.0.0.1', 3434, {
//     closeHandler: (id, remoteClose)=> {console.log(id, remoteClose, 'closed!');},
//     frameHandler: df.retrieveFrame,
//     connHandler: (id)=> {console.log(id);},
//     onFrameReady: (frame)=> {console.log(frame);}
//   });
// }

module.exports = Connection;